<?php
/**
 * Model.php
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@mygem.org so we can send you a copy immediately.
 *
 * @copyright   Copyright (c) 2012, MyGem <info@mygem.org>
 * @package     MyGem\Model
 */


class MyGem_Model_ORM extends MyGem_Base
{

    const REPLACE = 1;
    const INSERT = 2;
    const UPDATE = 3;
    const DELETE = 4;

    protected $id;
    protected $_table = NULL;
    protected $_primaryKeys = array('id');
    protected $_persistMode = self::REPLACE;
    protected $_cascadePersist = FALSE;
    protected $_cascadePopulate = TRUE;

    public function __construct()
    {
        if ($this->_table === NULL) {
            $this->_table = get_class($this);
        }
    }

    public function persist()
    {
        $db = MyGem_Registry::get('db');
        $sql = $this->toSQL();
        trigger_error($sql);
        $result = $db->query($sql);
        $this->id = $db->lastInsertId();
        if ($this->shouldAudit() && get_class($this) != 'Audit' && get_class($this) != 'AuditValue') {
            MyGem_ORM::audit($this);
        }
        return $this;
    }

    public function shouldAudit()
    {
        return FALSE;
    }

    public function audit($obj)
    {
        $audit = new Audit();
        $audit->objectClass = get_class($obj);
        $audit->objectId = $obj->id;
        $user = MyGem_Registry::get('user');
        $audit->userId = ($user && $user->id > 0)?(int)$user->id:0;
        $audit->type = $obj->_persistMode;
        $audit->dateTime = date('Y-m-d H:i:s');
        $audit->persist();
        if ($obj instanceof self) {
            foreach ($obj->ModelFields() as $field) {
                $auditValue = new AuditValue();
                $auditValue->auditId = $audit->id;
                $auditValue->key = $field;
                if (is_object($obj->$field)) {
                    $auditValue->value = get_class($obj->$field);
                }
                else {
                    $auditValue->value = (string)$obj->$field;
                }
                $auditValue->persist();
            }
        }
    }

    public function ModelFields()
    {
        $class = new ReflectionClass($this);
        $properties = $class->getProperties();
        $fields = array();
        foreach ($properties as $property) {
            if (substr($property->name,0,1) == '_') continue;
            $fields[] = $property->name;
        }
        return $fields;
    }

    public function toSql()
    {
        $db = MyGem_Registry::get('db');
        $fields = $this->ModelFields();
        $sql = '';

        switch ($this->_persistMode) {
            case self::REPLACE:
                $sql = "REPLACE INTO `{$this->_table}` SET ";
                break;
            case self::INSERT:
                $sql = "INSERT INTO `{$this->_table}` SET ";
                break;
            case self::UPDATE:
                $sql = "UPDATE `{$this->_table}` SET ";
                break;
            case self::DELETE:
                $sql = "DELETE FROM `{$this->_table}` ";
                $id = (int)$this->id;
                if ($id > 0) {
                    $sql .= "WHERE id = {$id}";
                    return $sql;
                }
                break;
        }

        $values = array();
        for ($i = 0, $ctr = count($fields); $i < $ctr; $i++) {
            $field = $fields[$i];
            $val = $this->__get($field);
            if ($val === NULL) continue;
            if (is_object($val)) {
                if ($val instanceof MyGem_Model && $this->_cascadePersist === TRUE) {
                    $val->_persistMode = $this->_persistMode;
                    $val->persist();
                }
                continue;
            }
            else if (is_array($val)) {
                foreach ($val as $item) {
                    if ($item instanceof MyGem_Model) {
                        $item->persist();
                    }
                }
                continue;
            }
            $values[] = "`$field` = " . $db->quote($val);
        }

        if ($this->_persistMode == self::DELETE) {
            $sql .= 'WHERE ' . implode(' AND ',$values);
        }
        else {
            $sql .= implode(', ',$values);
        }
        return $sql;
    }

    public function toArray()
    {
        $ret = array();
        foreach($this->ModelFields() as $value) {
            if ($this->$value instanceof self) {
                $ret[$value] = $this->$value->toArray();
            }
            else {
                $ret[$value] = $this->$value;
            }
        }
        return $ret;
    }

    public function populate()
    {
        $id = (int)$this->id;
        if ($id <= 0) return FALSE;
        $sql = "SELECT * FROM {$this->_table} WHERE id = {$id}";
        $db = MyGem_Registry::get('db');
        if ($row = $db->selectSingle($sql)) {
            $this->populateWithArray($row);
            return TRUE;
        }
    }

    public function populateWithArray($data)
    {
        foreach($data as $key=>$value) {
            if ($this->$key instanceof MyGem_Model) {
                $this->$key->populateWithArray($value);
            }
            else {
                $this->__set($key, $value);
            }
        }
    }

    public function getAll()
    {
        $db = MyGem_Registry::get('db');
        $sql = "SELECT * FROM {$this->_table} WHERE 1";
        return $db->select($sql);
    }

}

